use bevy::prelude::*;
use bevy::render::primitives::{Frustum, HalfSpace, Aabb};
use bevy::input::mouse::{MouseMotion, MouseWheel};
use bevy::pbr::{MaterialMeshBundle, DirectionalLightBundle};

// 可选择实体的标记组件
#[derive(Component)]
struct Selectable;

// 已选中实体的标记组件
#[derive(Component)]
struct Selected;

// 框选状态资源
#[derive(Resource)]
struct SelectionState {
    is_selecting: bool,
    start_pos: Vec2,
    current_pos: Vec2,
    frustum: Option<Frustum>,
}

// 自定义相机控制器组件
#[derive(Component)]
struct OrbitCamera {
    focus: Vec3,
    radius: f32,
    orbit_speed: f32,
    pan_speed: f32,
    zoom_speed: f32,
}

impl Default for OrbitCamera {
    fn default() -> Self {
        Self {
            focus: Vec3::ZERO,
            radius: 10.0,
            orbit_speed: 0.25,
            pan_speed: 0.25,
            zoom_speed: 2.0,
        }
    }
}

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .insert_resource(SelectionState {
            is_selecting: false,
            start_pos: Vec2::ZERO,
            current_pos: Vec2::ZERO,
            frustum: None,
        })
        .add_systems(Startup, setup)
        .add_systems(Update, (orbit_camera_system, selection_system))
        .run();
}

// 设置 3D 场景，包括相机和可选择立方体
fn setup(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    // 生成带有轨道控制的 3D 相机
    commands.spawn((
        Camera3d::default(),
        Transform::from_xyz(0.0, 5.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y),
        // 添加自定义轨道相机控制器
        OrbitCamera {
            focus: Vec3::ZERO,
            radius: 10.0,
            orbit_speed: 0.25,
            zoom_speed: 2.0,
            pan_speed: 0.25,
            ..default()
        },
    ));

    // 生成带有 AABB 的可选择立方体
    for i in -2..3 {
        let mesh = meshes.add(Cuboid::new(1.0, 1.0, 1.0));
        let aabb = Aabb::from_min_max(Vec3::new(-0.5, -0.5, -0.5), Vec3::new(0.5, 0.5, 0.5));
        commands.spawn((
            MaterialMeshBundle {
                mesh,
                material: materials.add(StandardMaterial {
                    base_color: Color::WHITE,
                    ..default()
                }),
                transform: Transform::from_xyz(i as f32 * 2.0, 0.0, 0.0),
                ..default()
            },
            Selectable,
            aabb,
        ));
    }
    
    // 添加光源
    commands.spawn(DirectionalLightBundle {
        directional_light: DirectionalLight {
            illuminance: 10000.0,
            shadows_enabled: true,
            ..default()
        },
        transform: Transform::from_xyz(4.0, 8.0, 4.0).looking_at(Vec3::ZERO, Vec3::Y),
        ..default()
    });
}

// 轨道相机控制系统
fn orbit_camera_system(
    time: Res<Time>,
    mut mouse_motion_events: EventReader<MouseMotion>,
    mouse_button_input: Res<ButtonInput<MouseButton>>,
    mut scroll_events: EventReader<MouseWheel>,
    mut query: Query<(&mut Transform, &mut OrbitCamera)>,
) {
    let dt = time.delta_secs();
    let mut mouse_delta = Vec2::ZERO;
    
    // 累积鼠标移动
    for event in mouse_motion_events.read() {
        mouse_delta += event.delta;
    }
    
    // 相机数据
    for (mut transform, mut orbit) in &mut query {
        // 平移(右键拖动)
        if mouse_button_input.pressed(MouseButton::Right) {
            let pan_speed = orbit.pan_speed * orbit.radius;
            let right = transform.right();
            let up = transform.up();
            orbit.focus += -right * mouse_delta.x * pan_speed * dt;
            orbit.focus += up * mouse_delta.y * pan_speed * dt;
        }
        
        // 旋转(中键拖动)
        if mouse_button_input.pressed(MouseButton::Middle) {
            let mut angles = Vec2::ZERO;
            angles.x = -mouse_delta.y * orbit.orbit_speed * dt;
            angles.y = -mouse_delta.x * orbit.orbit_speed * dt;
            
            // 从焦点到相机的向量
            let focus_to_camera = transform.translation - orbit.focus;
            
            // 转换为球坐标
            let mut radius = focus_to_camera.length();
            let mut theta = (focus_to_camera.y / radius).acos();
            let mut phi = focus_to_camera.z.atan2(focus_to_camera.x);
            
            // 应用角度变化
            theta = (theta + angles.x).clamp(0.1, std::f32::consts::PI - 0.1);
            phi += angles.y;
            
            // 缩放调整
            for event in scroll_events.read() {
                radius -= event.y * orbit.zoom_speed;
                radius = radius.max(1.0);
            }
            
            // 更新轨道半径
            orbit.radius = radius;
            
            // 更新相机位置
            let sin_theta = theta.sin();
            transform.translation = orbit.focus + Vec3::new(
                radius * sin_theta * phi.cos(),
                radius * theta.cos(),
                radius * sin_theta * phi.sin(),
            );
            
            // 看向焦点
            transform.look_at(orbit.focus, Vec3::Y);
        }
        
        // 缩放(滚轮)
        let mut scroll = 0.0;
        for event in scroll_events.read() {
            scroll += event.y;
        }
        
        if scroll != 0.0 {
            orbit.radius -= scroll * orbit.zoom_speed;
            orbit.radius = orbit.radius.max(1.0);
            
            // 更新相机位置
            let dir = (transform.translation - orbit.focus).normalize();
            transform.translation = orbit.focus + dir * orbit.radius;
        }
    }
}

// 处理框选逻辑并绘制与框选区域对应的自定义视锥
fn selection_system(
    mouse_button_input: Res<ButtonInput<MouseButton>>,
    windows: Query<&Window>,
    camera_query: Query<(&Camera, &GlobalTransform)>,
    mut selection_state: ResMut<SelectionState>,
    mut gizmos: Gizmos,
    selectable_query: Query<(Entity, &GlobalTransform, &Aabb), With<Selectable>>,
    mut commands: Commands,
) {
    let Ok(window) = windows.single() else {
        return;
    };
    let Ok((camera, camera_transform)) = camera_query.single() else {
        return;
    };

    // 获取鼠标光标位置（屏幕坐标）
    let cursor_pos = window.cursor_position().unwrap_or(Vec2::ZERO);

    // 按下左键开始框选
    if mouse_button_input.just_pressed(MouseButton::Left) {
        selection_state.is_selecting = true;
        selection_state.start_pos = cursor_pos;
        selection_state.current_pos = cursor_pos;
        selection_state.frustum = None;
    }

    // 更新框选时的当前鼠标位置
    if selection_state.is_selecting {
        selection_state.current_pos = cursor_pos;

        // 计算选择矩形（屏幕空间）
        let min = selection_state.start_pos.min(selection_state.current_pos);
        let max = selection_state.start_pos.max(selection_state.current_pos);

        // 在屏幕上绘制矩形选框
        draw_screen_rect(&mut gizmos, camera, camera_transform, min, max);

        // 松开左键时结束框选并检测选中物体
        if mouse_button_input.just_released(MouseButton::Left) {
            selection_state.is_selecting = false;

            // 创建与框选区域对应的视锥
            let frustum = create_selection_frustum(min, max, camera, camera_transform);
            selection_state.frustum = Some(frustum);

            // 检查每个可选择实体
            for (entity, transform, aabb) in selectable_query.iter() {
                // 将 AABB 转换到世界空间
                let world_aabb = transform_aabb(aabb, transform.compute_matrix());

                // 判断是否与视锥相交
                if is_aabb_in_frustum(&world_aabb, &frustum) {
                    commands.entity(entity).insert(Selected);
                } else {
                    commands.entity(entity).remove::<Selected>();
                }
            }
        }
    }

    // 如果有保存的视锥，绘制它
    if let Some(frustum) = &selection_state.frustum {
        draw_frustum(&mut gizmos, frustum);
    }
}

// 绘制屏幕空间上的矩形框
fn draw_screen_rect(
    gizmos: &mut Gizmos,
    camera: &Camera,
    camera_transform: &GlobalTransform,
    min: Vec2,
    max: Vec2,
) {
    // 定义矩形的四个角
    let corners = [
        min,
        Vec2::new(max.x, min.y),
        max,
        Vec2::new(min.x, max.y),
    ];

    // 将屏幕坐标转换为世界坐标
    let world_corners: Vec<Vec3> = corners
        .iter()
        .filter_map(|&p| {
            camera.viewport_to_world(camera_transform, p)
                .ok()
                .and_then(|ray| {
                    let distance = ray.origin.z / ray.direction.z * 0.9;
                    Some(ray.origin - distance * ray.direction)
                })
        })
        .collect();

    if world_corners.len() == 4 {
        // 绘制矩形边框（黄色）
        gizmos.line(world_corners[0], world_corners[1], Color::srgb(1.0, 1.0, 0.0));
        gizmos.line(world_corners[1], world_corners[2], Color::srgb(1.0, 1.0, 0.0));
        gizmos.line(world_corners[2], world_corners[3], Color::srgb(1.0, 1.0, 0.0));
        gizmos.line(world_corners[3], world_corners[0], Color::srgb(1.0, 1.0, 0.0));
    }
}

// 创建与框选区域对应的视锥
fn create_selection_frustum(
    min: Vec2,
    max: Vec2,
    camera: &Camera,
    camera_transform: &GlobalTransform,
) -> Frustum {
    // 相机位置
    let camera_pos = camera_transform.translation();
    
    // 计算框选矩形的四个角的世界坐标
    let screen_corners = [
        Vec2::new(min.x, min.y),  // 左下
        Vec2::new(max.x, min.y),  // 右下
        Vec2::new(max.x, max.y),  // 右上
        Vec2::new(min.x, max.y),  // 左上
    ];
    
    // 将屏幕坐标转换为世界空间中的射线
    let mut world_rays = Vec::new();
    for corner in &screen_corners {
        if let Ok(ray) = camera.viewport_to_world(camera_transform, *corner) {
            world_rays.push(ray);
        }
    }
    
    // 如果无法获取所有射线，返回默认视锥体
    if world_rays.len() != 4 {
        return Frustum::default();
    }
    
    // 创建视锥平面
    let mut half_spaces = [HalfSpace::default(); 6];
    
    // 计算侧面的半空间
    for i in 0..4 {
        let dir1 = world_rays[i].direction;
        let dir2 = world_rays[(i+1)%4].direction;
        
        // 使用两个方向的叉乘作为法线
        // 从 Dir3 转换为 Vec3
        let normal = Vec3::new(
            dir1.y * dir2.z - dir1.z * dir2.y,
            dir1.z * dir2.x - dir1.x * dir2.z,
            dir1.x * dir2.y - dir1.y * dir2.x,
        ).normalize();
        
        // 计算平面方程的d值
        let d = -normal.dot(camera_pos);
        
        // 创建半空间
        half_spaces[i] = HalfSpace::new(Vec4::new(normal.x, normal.y, normal.z, d));
    }
    
    // 添加近平面和远平面
    let near_distance = 0.1;  // 近平面距离
    let far_distance = 1000.0;  // 远平面距离
    
    // 相机前向方向作为近平面的法线
    let forward = camera_transform.forward();
    
    // 近平面
    half_spaces[4] = HalfSpace::new(Vec4::new(
        forward.x, 
        forward.y, 
        forward.z, 
        -forward.dot(camera_pos + forward * near_distance)
    ));
    
    // 远平面，与近平面相反方向
    half_spaces[5] = HalfSpace::new(Vec4::new(
        -forward.x, 
        -forward.y, 
        -forward.z, 
        forward.dot(camera_pos + forward * far_distance)
    ));
    
    Frustum { half_spaces }
}

// 绘制视锥
fn draw_frustum(gizmos: &mut Gizmos, frustum: &Frustum) {
    let corners = compute_frustum_corners(frustum);

    if corners.len() != 8 {
        return;
    }

    // 绘制近裁剪面（红色）
    gizmos.line(corners[0], corners[1], Color::srgb(1.0, 0.0, 0.0));
    gizmos.line(corners[1], corners[2], Color::srgb(1.0, 0.0, 0.0));
    gizmos.line(corners[2], corners[3], Color::srgb(1.0, 0.0, 0.0));
    gizmos.line(corners[3], corners[0], Color::srgb(1.0, 0.0, 0.0));

    // 绘制远裁剪面（蓝色）
    gizmos.line(corners[4], corners[5], Color::srgb(0.0, 0.0, 1.0));
    gizmos.line(corners[5], corners[6], Color::srgb(0.0, 0.0, 1.0));
    gizmos.line(corners[6], corners[7], Color::srgb(0.0, 0.0, 1.0));
    gizmos.line(corners[7], corners[4], Color::srgb(0.0, 0.0, 1.0));

    // 连接近裁剪面和远裁剪面（绿色）
    gizmos.line(corners[0], corners[4], Color::srgb(0.0, 1.0, 0.0));
    gizmos.line(corners[1], corners[5], Color::srgb(0.0, 1.0, 0.0));
    gizmos.line(corners[2], corners[6], Color::srgb(0.0, 1.0, 0.0));
    gizmos.line(corners[3], corners[7], Color::srgb(0.0, 1.0, 0.0));
}

// 计算视锥的八个顶点
fn compute_frustum_corners(frustum: &Frustum) -> Vec<Vec3> {
    let half_spaces = &frustum.half_spaces;
    let mut corners = Vec::new();
    
    // 计算近平面的四个顶点
    if let Some(near_corners) = compute_plane_intersections(&half_spaces[4], &[
        &half_spaces[0], &half_spaces[1], &half_spaces[2], &half_spaces[3]
    ]) {
        corners.extend(near_corners);
    } else {
        return Vec::new();
    }
    
    // 计算远平面的四个顶点
    if let Some(far_corners) = compute_plane_intersections(&half_spaces[5], &[
        &half_spaces[0], &half_spaces[1], &half_spaces[2], &half_spaces[3]
    ]) {
        corners.extend(far_corners);
    } else {
        return Vec::new();
    }
    
    corners
}

// 计算一个平面与其他四个平面在各个交线上的四个交点
fn compute_plane_intersections(
    base_plane: &HalfSpace,
    other_planes: &[&HalfSpace; 4]
) -> Option<Vec<Vec3>> {
    let mut corners = Vec::new();
    
    // 计算相邻平面两两交线与基准平面的交点
    for i in 0..4 {
        let p1 = other_planes[i];
        let p2 = other_planes[(i+1)%4];
        
        if let Some(corner) = intersect_three_planes(base_plane, p1, p2) {
            corners.push(corner);
        } else {
            return None;
        }
    }
    
    Some(corners)
}

// 计算三个平面的交点
fn intersect_three_planes(p1: &HalfSpace, p2: &HalfSpace, p3: &HalfSpace) -> Option<Vec3> {
    let n1 = p1.normal_d();
    let n2 = p2.normal_d();
    let n3 = p3.normal_d();
    
    let normal1 = Vec3::new(n1.x, n1.y, n1.z);
    let normal2 = Vec3::new(n2.x, n2.y, n2.z);
    let normal3 = Vec3::new(n3.x, n3.y, n3.z);
    
    // 计算行列式
    let det = normal1.dot(normal2.cross(normal3));
    
    // 如果行列式接近零，则平面可能平行，没有唯一交点
    if det.abs() < 1e-6 {
        return None;
    }
    
    // 计算交点
    let d1 = n1.w;
    let d2 = n2.w;
    let d3 = n3.w;
    
    let c1 = normal2.cross(normal3) * d1;
    let c2 = normal3.cross(normal1) * d2;
    let c3 = normal1.cross(normal2) * d3;
    
    let point = (c1 + c2 + c3) / det;
    
    // 取负号，因为平面方程为 normal·point + d = 0
    Some(-point)
}

// 检查 AABB 是否在视锥内
fn is_aabb_in_frustum(aabb: &Aabb, frustum: &Frustum) -> bool {
    for half_space in &frustum.half_spaces {
        let normal_d = half_space.normal_d();
        let normal = Vec3::new(normal_d.x, normal_d.y, normal_d.z);
        
        // 检查 AABB 是否完全在半空间外部
        let min = aabb.min();
        let max = aabb.max();
        let extreme_point = Vec3::new(
            if normal.x > 0.0 { max.x } else { min.x },
            if normal.y > 0.0 { max.y } else { min.y },
            if normal.z > 0.0 { max.z } else { min.z },
        );

        // 计算到平面的有符号距离
        let signed_distance = normal.dot(extreme_point) + normal_d.w;
        if signed_distance < 0.0 {
            return false;
        }
    }
    true
}

// 变换 AABB
fn transform_aabb(aabb: &Aabb, transform: Mat4) -> Aabb {
    let min = aabb.min();
    let max = aabb.max();

    // 计算 AABB 的八个角
    let corners = [
        transform.transform_point3(Vec3::new(min.x, min.y, min.z)),
        transform.transform_point3(Vec3::new(max.x, min.y, min.z)),
        transform.transform_point3(Vec3::new(min.x, max.y, min.z)),
        transform.transform_point3(Vec3::new(max.x, max.y, min.z)),
        transform.transform_point3(Vec3::new(min.x, min.y, max.z)),
        transform.transform_point3(Vec3::new(max.x, min.y, max.z)),
        transform.transform_point3(Vec3::new(min.x, max.y, max.z)),
        transform.transform_point3(Vec3::new(max.x, max.y, max.z)),
    ];

    // 找出变换后角的最小和最大坐标
    let mut new_min = Vec3::splat(f32::MAX);
    let mut new_max = Vec3::splat(f32::MIN);

    for corner in corners {
        new_min = new_min.min(corner);
        new_max = new_max.max(corner);
    }

    Aabb::from_min_max(new_min, new_max)
}